#include "Curve_face.h"

void Curve_face::ReadPoints()
{
	P_Control[0][0].x = 20; P_Control[0][0].y = 0; P_Control[0][0].z = 200;
	P_Control[0][1].x = 0; P_Control[0][1].y = 100; P_Control[0][1].z = 150;
	P_Control[0][2].x = -130; P_Control[0][2].y = 100; P_Control[0][2].z = 50;
	P_Control[0][3].x = -250; P_Control[0][3].y = 50; P_Control[0][3].z = 0;

	P_Control[1][0].x = 100; P_Control[1][0].y = 100; P_Control[1][0].z = 150;
	P_Control[1][1].x = 30; P_Control[1][1].y = 100; P_Control[1][1].z = 100;
	P_Control[1][2].x = -40; P_Control[1][2].y = 100; P_Control[1][2].z = 50;
	P_Control[1][3].x = -110; P_Control[1][3].y = 100; P_Control[1][3].z = 0;

	P_Control[2][0].x = 280; P_Control[2][0].y = 90; P_Control[2][0].z = 140;
	P_Control[2][1].x = 110; P_Control[2][1].y = 120; P_Control[2][1].z = 80;
	P_Control[2][2].x = 30; P_Control[2][2].y = 130; P_Control[2][2].z = 30;
	P_Control[2][3].x = -100; P_Control[2][3].y = 150; P_Control[2][3].z = -50;

	P_Control[3][0].x = 350; P_Control[3][0].y = 30; P_Control[3][0].z = 150;
	P_Control[3][1].x = 200; P_Control[3][1].y = 150; P_Control[3][1].z = 50;
	P_Control[3][2].x = 50; P_Control[3][2].y = 200; P_Control[3][2].z = 0;
	P_Control[3][3].x = 0; P_Control[3][3].y = 100; P_Control[3][3].z = -70;
}

void Curve_face::ReadM_Coe()
{
	M[0][0] = -1; M[0][1] = 3; M[0][2] = -3; M[0][3] = 1;
	M[1][0] = 3; M[1][1] = -6; M[1][2] = 3; M[1][3] = 0;
	M[2][0] = -3; M[2][1] = 3; M[2][2] = 0; M[2][3] = 0;
	M[3][0] = 1; M[3][1] = 0; M[3][2] = 0; M[3][3] = 0;
}

void Curve_face::ObliqueProjection()
{
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 4; j++) {
			P2[i][j].x = P_Control[i][j].x - P_Control[i][j].z / sqrt(2.0);
			P2[i][j].y = P_Control[i][j].y - P_Control[i][j].z / sqrt(2.0);
		}
	}
}
void Curve_face::LeftMatrix(E_Point3 P0[][4])
{
	E_Point3 T[4][4];
	int i, j;
	for (i = 0; i < 4; i++) {
		for (j = 0; j < 4; j++) {
			T[i][j] = M[i][0] * P0[0][j] + M[i][1] * P0[1][j]
				+ M[i][2] * P0[2][j] + M[i][3] * P0[3][j];
		}
	}
	for (i = 0; i < 4; i++) {
		for (j = 0; j < 4; j++) {
			P_Control[i][j] = T[i][j];
		}
	}
}

void Curve_face::RightMatrix(E_Point3 P0[][4])
{
	E_Point3 T[4][4];
	int i, j;
	for (i = 0; i < 4; i++) {
		for (j = 0; j < 4; j++) {
			T[i][j] = P0[i][0] * MT[0][j] + MT[1][j] * P0[i][1]
				+ MT[2][j] * P0[i][2] + MT[3][j] * P0[i][3];
		}
	}
	for (i = 0; i < 4; i++) {
		for (j = 0; j < 4; j++) {
			P_Control[i][j] = T[i][j];
		}
	}
}

void Curve_face::Transpose()
{
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 4; j++) {
			MT[j][i] = M[i][j];
		}
	}
}

void Curve_face::DrawControl()
{
	setlinecolor(BLUE);
	setlinestyle(PS_SOLID, 2);
	
	ObliqueProjection();
	for (int i = 0; i < 4; i++) {
		moveto(P2[i][0].x, P2[i][0].y);
		for (int j = 1; j < 4; j++) {
			lineto(P2[i][j].x, P2[i][j].y);
		}
	}
	for (int j = 0; j < 4; j++) {
		moveto(P2[0][j].x, P2[0][j].y);
		for (int i = 1; i < 4; i++) {
			lineto(P2[i][j].x, P2[i][j].y);
		}
	}
}

void Curve_face::DrawCurveFace()
{
	setlinecolor(BLACK);
	setlinestyle(PS_SOLID, 2);
	ReadM_Coe();
	double u, v, u1, u2, u3, u4, v1, v2, v3, v4;
	LeftMatrix(P_Control);
	Transpose();
	RightMatrix(P_Control);
	ObliqueProjection();
	for (u = 0; u <= 1; u += 0.01) {
		for (v = 0; v <= 1; v += 0.01) {
			u1 = u * u * u; u2 = u * u; u3 = u; u4 = 1; v1 = v * v * v; v2 = v * v; v3 = v; v4 = 1;
			E_Point ScreenPoint = 
				  (u1 * P2[0][0] + u2 * P2[1][0] + u3 * P2[2][0] + u4 * P2[3][0]) * v1
				+ (u1 * P2[0][1] + u2 * P2[1][1] + u3 * P2[2][1] + u4 * P2[3][1]) * v2
				+ (u1 * P2[0][2] + u2 * P2[1][2] + u3 * P2[2][2] + u4 * P2[3][2]) * v3
				+ (u1 * P2[0][3] + u2 * P2[1][3] + u3 * P2[2][3] + u4 * P2[3][3]) * v4;
			
			if (v == 0)
				moveto(ScreenPoint.x, ScreenPoint.y);
			else
				lineto(ScreenPoint.x, ScreenPoint.y);
		}
	}
	for (v = 0; v <= 1; v += 0.01) {
		for (u = 0; u <= 1; u += 0.01) {
			u1 = u * u * u; u2 = u * u; u3 = u; u4 = 1; v1 = v * v * v; v2 = v * v; v3 = v; v4 = 1;
			E_Point ScreenPoint =
				  (u1 * P2[0][0] + u2 * P2[1][0] + u3 * P2[2][0] + u4 * P2[3][0]) * v1
				+ (u1 * P2[0][1] + u2 * P2[1][1] + u3 * P2[2][1] + u4 * P2[3][1]) * v2
				+ (u1 * P2[0][2] + u2 * P2[1][2] + u3 * P2[2][2] + u4 * P2[3][2]) * v3
				+ (u1 * P2[0][3] + u2 * P2[1][3] + u3 * P2[2][3] + u4 * P2[3][3]) * v4;
			if (u == 0)
				moveto(ScreenPoint.x, ScreenPoint.y);
			else
				lineto(ScreenPoint.x, ScreenPoint.y);
		}
	}
}
